package com.grandstream.website.app.mybatis.plugins;

import java.beans.Statement;
import java.lang.reflect.Field;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.util.Properties;

import org.apache.ibatis.builder.xml.dynamic.DynamicSqlSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.MappedStatement.Builder;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

@Intercepts({@Signature(type = Executor.class,args={
	MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}, method = "query"
						)
			})
public class PagePlugin implements Interceptor{
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		// TODO Auto-generated method stub
		Object [] objs =invocation.getArgs();
		if(objs !=null  && objs[0]!=null && objs[2]!=null && objs[2] != RowBounds.DEFAULT){ 
			resolveInterceptObj(objs);
		}
		return invocation.proceed();
	}
	
	private void resolveInterceptObj(Object [] objs){
		//objs[2] 为分页对象（RowBounds）如果是默认（0到最大的  就是显示所有记录）的情况 不处理
		RowBounds rowBounds =(RowBounds)objs[2];   //分页对象
		MappedStatement ms =(MappedStatement)objs[0];  //statement对象
		BoundSql newBoundSql =createNewBoundSqlByPageSql(ms,objs[1],rowBounds);
		SqlSource newSqlSource =new pageSqlSource(newBoundSql);
		MappedStatement newMs =copyNewMappedStatement(ms,newSqlSource);
		objs[0]=newMs;                 //使用逻辑分页 mappedstatement
		objs[2] =RowBounds.DEFAULT;   //mybatis 使用物理分页，需设置成默认分页
	}

	@Override
	public Object plugin(Object target) {
		// TODO Auto-generated method stub
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {
		// TODO Auto-generated method stub
		
	}
	
	/**
	 * @see 根据mappedstatment找到执行的 sql 语句 ms.getBoundSql(parameterObject); 其中 根据parameterObject 查找出动态的 sql
	 * eg:   ms.getBoundSql(null)  sql: select * from A   ； ms.getBoundSql(parameterObjcet)  sql: select * from A where status =?
	 * @param ms
	 * @param parameterObject
	 * @param rowBounds
	 * @return
	 */
	private BoundSql createNewBoundSqlByPageSql(MappedStatement ms,Object parameterObject,RowBounds rowBounds){
		int limit =rowBounds.getLimit();
		int offset =rowBounds.getOffset();
		BoundSql boundSql =ms.getBoundSql(parameterObject);
		String sql =boundSql.getSql();
			StringBuilder sb =new StringBuilder();
			sb.append(sql);
			sb.append(" limit "+limit+" offset "+offset);
		BoundSql newBoundSql =new BoundSql(ms.getConfiguration(),sb.toString(),
											boundSql.getParameterMappings(),boundSql.getParameterObject());
		return newBoundSql;
	}
	
	private MappedStatement copyNewMappedStatement(MappedStatement ms,  
            SqlSource newSqlSource) {  
        Builder builder = new MappedStatement.Builder(ms.getConfiguration(),  
                ms.getId(), newSqlSource, ms.getSqlCommandType());  
        builder.resource(ms.getResource());  
        builder.fetchSize(ms.getFetchSize());  
        builder.statementType(ms.getStatementType());  
        builder.keyGenerator(ms.getKeyGenerator());  
        builder.keyProperty(ms.getKeyProperty());  
        builder.timeout(ms.getTimeout());  
        builder.parameterMap(ms.getParameterMap());  
        builder.resultMaps(ms.getResultMaps());  
        builder.cache(ms.getCache());  
        MappedStatement newMs = builder.build();  
        return newMs;  
    }  
  
	
	private  class pageSqlSource implements SqlSource{
		BoundSql boundSql ;
		
		public pageSqlSource(BoundSql _boundSql){
			boundSql=_boundSql;
		}
		@Override
		public BoundSql getBoundSql(Object parameterObject) {
			// TODO Auto-generated method stub
			return boundSql;
		}
		
	}

	public static void main(String[] args) {
		RowBounds b =new RowBounds();
		RowBounds b1 =new RowBounds();
		System.out.println(b.equals(b1));
	}
}
